package com.leo.train.business.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leo.train.business.dto.DailySeatQueryDto;
import com.leo.train.business.dto.SeatSellDto;
import com.leo.train.business.entity.DailyCarriage;
import com.leo.train.business.entity.DailySeat;
import com.leo.train.business.entity.Seat;
import com.leo.train.business.mapper.DailyCarriageMapper;
import com.leo.train.business.mapper.DailySeatMapper;
import com.leo.train.business.mapper.SeatMapper;
import com.leo.train.business.service.DailySeatService;
import com.leo.train.business.service.TrainInfoService;
import com.leo.train.business.vo.DailySeatVo;
import com.leo.train.business.vo.SeatSellVo;
import com.leo.train.common.enums.SeatColEnum;
import com.leo.train.common.enums.SeatTypeEnum;
import com.leo.train.common.exception.BusinessException;
import com.leo.train.common.exception.BusinessExceptionEnum;
import com.leo.train.common.resp.PageResult;
import com.leo.train.common.util.SnowUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DailySeatServiceImpl implements DailySeatService {
    @Autowired
    private DailySeatMapper dailySeatMapper;
    @Autowired
    private DailyCarriageMapper dailyCarriageMapper;
    @Autowired
    private SeatMapper seatMapper;
    @Autowired
    private TrainInfoService trainInfoService;
    @Override
    public void save(DailySeat dailySeat) {
        Long id = dailySeat.getId();
        if (id == null) {
            // 新增
            dailySeat.setId(SnowUtil.getSnowflakeNextId());
            dailySeat.setCreateTime(new Date());
            dailySeat.setUpdateTime(new Date());
            dailySeatMapper.insert(dailySeat);
        } else {
            // 修改
            dailySeat.setUpdateTime(new Date());
            dailySeatMapper.update(dailySeat);
        }
    }

    @Override
    public void deleteById(Long id) {
        dailySeatMapper.deleteById(id);
    }

    @Override
    public PageResult<DailySeatVo> list(DailySeatQueryDto dailySeatQueryDto) {
        PageHelper.startPage(dailySeatQueryDto.getPage(), dailySeatQueryDto.getPageSize());
        Page<DailySeat> page = dailySeatMapper.list(dailySeatQueryDto);
        List<DailySeatVo> seatVoList = page.getResult().stream().map(dailySeat -> {
            DailySeatVo dailySeatVo = new DailySeatVo();
            BeanUtils.copyProperties(dailySeat, dailySeatVo);
            dailySeatVo.setSeatTypeName(SeatTypeEnum.getEnumByCode(dailySeat.getSeatType()).getDesc());
            dailySeatVo.setColType(SeatColEnum.getEnumByCode(dailySeat.getCol()).getDesc());
            return dailySeatVo;
        }).collect(Collectors.toList());
        return new PageResult<>(page.getTotal(), seatVoList);
    }

    @Override
    public DailySeatVo detail(Long id) {
        DailySeat dailySeat = dailySeatMapper.selectById(id);
        if (dailySeat == null) {
            throw new BusinessException(BusinessExceptionEnum.BUSINESS_SEAT_NOT_EXIST);
        }
        DailySeatVo dailySeatVo = new DailySeatVo();
        BeanUtils.copyProperties(dailySeat, dailySeatVo);
        dailySeatVo.setSeatTypeName(SeatTypeEnum.getEnumByCode(dailySeat.getSeatType()).getDesc());
        dailySeatVo.setColType(SeatColEnum.getEnumByCode(dailySeat.getCol()).getDesc());
        return dailySeatVo;
    }

    @Override
    @Transactional // 开启事务注解
    public void generateSeats(String trainCode) {
        Date now = new Date();
        // 1. 先删除trainCode关联的所有座位信息
        dailySeatMapper.deleteByTrainCode(trainCode);
        // 2. 根据trainCode查询对应的所有车厢
        List<DailyCarriage> dailyCarriageList = dailyCarriageMapper.listByTrainCode(trainCode);
        log.info("查询到车厢：{}", dailyCarriageList);
        // 3.遍历车厢
        dailyCarriageList.forEach(dailyCarriage -> {
            // 3.1 拿到车厢数据：行数、座位类型(得到列数)
            int rowCount = dailyCarriage.getRowCount();
            String seatType = dailyCarriage.getSeatType();
            int seatIndex = 1; // 座位索引
            /*
                3.2 根据座位类型获取出所有的列
                比如车厢类型是一等座，则筛选出columnList=[A,C,D,F]
                比如车厢类型是二等座，则筛选出columnList=[A,B,C,D,F]
             */
            List<SeatColEnum> columnList = SeatColEnum.getColsByType(seatType);
            // 3.3 循环行数
            for (int row = 1; row <= rowCount; row++) {
                // 3.4 循环列数
                for(SeatColEnum col : columnList) {
                    // 3.5 生成座位
                    DailySeat dailySeat = new DailySeat();
                    dailySeat.setId(SnowUtil.getSnowflakeNextId());
                    dailySeat.setTrainCode(trainCode);
                    dailySeat.setCarriageIndex(dailyCarriage.getIndex());
                    // 如果是1位则补0，如1行A列则变为01行A列
                    dailySeat.setRow(StrUtil.fillBefore(String.valueOf(row), '0', 2));
                    dailySeat.setCol(col.getCode());
                    dailySeat.setSeatType(seatType);
                    dailySeat.setCarriageSeatIndex(seatIndex++); // 每个车厢的座位对应的索引
                    dailySeat.setCreateTime(now);
                    dailySeat.setUpdateTime(now);
                    dailySeatMapper.insert(dailySeat);
                }
            }
        });
    }

    @Override
    public void genDaily(Date date, String trainCode) {
        log.info("生成该车次的所有座位信息开始，trainCode: {}, date: {}", trainCode, DateUtil.formatDate(date));
        // 1. 先删除当前日期的trainCode关联的所有座位信息
        dailySeatMapper.deleteByTrainCodeByDate(date,trainCode);
        // 2. 根据trainCode查询基本数据表对应的所有座位
        List<Seat> seatList = seatMapper.listByTrainCode(trainCode);
        // 3. 查询有几个车站，方便座位索引售卖情况初始化
        int stationCount = trainInfoService.countStationByTrainCode(trainCode);
        // 3.1 构造售卖信息
        String sell = StrUtil.fillBefore("", '0', stationCount - 1);
        if(CollectionUtil.isEmpty(seatList)) {
            log.info("没有当前车次的座位基础数据，生成该车次的座位信息结束");
            return;
        }
        for(Seat seat : seatList) {
            Date now = new Date();
            DailySeat dailySeat = new DailySeat();
            BeanUtils.copyProperties(seat, dailySeat);
            dailySeat.setId(SnowUtil.getSnowflakeNextId());
            dailySeat.setTrainCode(trainCode);
            dailySeat.setDate(date);
            dailySeat.setCreateTime(now);
            dailySeat.setUpdateTime(now);
            // 售卖情况|将经过的车站用01拼接，0表示可卖，1表示已卖
            // 新增的一个售卖情况：默认是0，表示未卖，1表示已卖
            // 有几个车站，则默认有几个0
            dailySeat.setSell(sell);
            dailySeatMapper.insert(dailySeat);
        }
        log.info("生成该车次的所有座位信息结束，trainCode: {}, date: {}", trainCode, DateUtil.formatDate(date));
    }

    /**
     * 计算不同类型的座位数量
     * @param date
     * @param trainCode
     * @return
     */
    @Override
    public int countSeat(Date date, String trainCode,String seatType) {
        int count = dailySeatMapper.count(date, trainCode,seatType);
        // 如果查询结果为0，则表示该日期该车次该类型的座位不存在，则返回-1
        if(count == 0) {
            return  -1;
        }
        return count;
    }

    @Override
    public List<DailySeat> listByCarriage(Date date, String trainCode, Integer carriageIndex) {
        return dailySeatMapper.listByCarriage(date, trainCode, carriageIndex);
    }

    @Override
    public List<SeatSellVo> querySeatSell(SeatSellDto seatSellDto) {
        List<DailySeat> dailySeatList = dailySeatMapper.querySeatSell(seatSellDto);
        return BeanUtil.copyToList(dailySeatList, SeatSellVo.class);
    }
}
